﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Netfraction.Common.DataStorage;
using NetfractionHub.LocalMachine.BotCommands;
using NetfractionHub.Network.Protocol;
using NetfractionHub.Network.Protocol.BASE.Factory;
using NetfractionHub.Network.Protocol.UCMD.Factory;

namespace NetfractionHub.LocalMachine
{
	[BotNode(CommandPrefix="!")]
	[BotNode(CommandPrefix="+")]
	public class SecurityBot : BotNode
	{
		private static DataSource _dataSource;

		public SecurityBot()
		{
			AddCommand(new BotCommands.Handler.ListPermissions());
			AddCommand(new BotCommands.Handler.ListConfiguration());
			AddCommand(new BotCommands.Handler.SetPermission());
			AddCommand(new BotCommands.Handler.Uptime());
			AddCommand(new BotCommands.Handler.Kick());
			AddCommand(new BotCommands.Handler.Drop());
			AddCommand(new BotCommands.Handler.Ban());
			AddCommand(new BotCommands.Handler.MessageOfTheDay());
			AddCommand(new BotCommands.Handler.GetIPAddress());
			AddCommand(new BotCommands.Handler.GetClientId());
			AddCommand(new BotCommands.Handler.HubName());
			AddCommand(new BotCommands.Handler.Help());
			AddCommand(new BotCommands.Handler.RegisterUser());
			AddCommand(new BotCommands.Handler.UpdateRegistration());
			AddCommand(new BotCommands.Handler.SetPassword());
			AddCommand(new BotCommands.Handler.ResetPassword());
			AddCommand(new BotCommands.Handler.AddConnectionListener());
			AddCommand(new BotCommands.Handler.SaveSettings());
			AddCommand(new BotCommands.Handler.Role());
			AddCommand(new BotCommands.Handler.Hide());
			AddCommand(new BotCommands.Handler.Show());

			//CreateBotCIDS(); // Generate a CID for the security and operator bots
			this.Identity.ClientId = Settings.HubSettings.SecurityBot.ClientId;
			this.Identity.Description = Settings.HubSettings.SecurityBot.Description;
			this.Identity.NodeType = IdentityNodeTypes.Bot | IdentityNodeTypes.Operator | NetfractionHub.IdentityNodeTypes.Hidden;
			Version curVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
			this.Identity.ClientVersion = String.Format(System.Globalization.CultureInfo.InvariantCulture, "Netfraction Bot {0}.{1}", curVersion.Major, curVersion.Minor);
			this.Identity.MaximumUploadSpeed = 100 * 128 * 1024;    // 100 megabits per second
			this.Identity.HubOperatorCount = 1;
			this.SessionId = Settings.HubSettings.SecurityBot.SessionId;
			this.SecurityIdentity = Security.IdentityManager.GetIdentityByClientId(this.Identity.ClientId);
			this.Identity.Nickname = this.SecurityIdentity.Name;

			if (_dataSource == null)
				CreateDataSource();
		}

		public override void OnStart()
		{
			NetfractionHub.Network.ConnectionManager.OnClientConnected += new NetfractionHub.Network.ClientConnected(OnClientConnected);

			NetfractionHub.Network.ConnectionManager.SendNodeInformationToAll(this);
		}

		private static void CreateDataSource()
		{
			if (_dataSource != null)
				return;

			Version curVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

			_dataSource = new DataSource();

			_dataSource.Name = "SecurityBot";
			_dataSource.Version = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.{1}", curVersion.Major, curVersion.Minor);
			_dataSource.Guid = new Guid("96CEC634-3DE1-40bb-A0CE-0632F7D72F58");
			_dataSource.Author = "darkKlor";
			_dataSource.SourceLicence = "GPL v2.0";
			_dataSource.UpdateUrl = "";
			_dataSource.SiteUrl = "http://netfraction.codeplex.com/";
		}

		#region Singleton Pattern
		// Use singleton pattern.
		private static SecurityBot _instance;

		/// <summary>
		/// Obtain singleton instance of ConnectionManager
		/// </summary>
		/// <returns></returns>
		public static SecurityBot GetInstance()
		{
			// Check instance
			if (SecurityBot._instance == null)
			{
				// Initialise instance
				SecurityBot._instance = new SecurityBot();
			}

			// Return instance
			return SecurityBot._instance;
		}
		#endregion Singleton Pattern

		private static void CreateBotCIDS()
		{
			/* Generate a CID for the security and operator bots
			Network.Protocol.TIGR.Security.Cryptography.Tiger hashAlgorithm = Network.Protocol.TIGR.Security.Cryptography.Tiger.Create();
			hashAlgorithm.Initialize();
			byte[] hash = hashAlgorithm.ComputeHash(System.Text.Encoding.UTF8.GetBytes("the security bot private id"));
			System.Diagnostics.Debug.WriteLine(Base32.Encode(hash).Substring(0, 39));
			hash = hashAlgorithm.ComputeHash(System.Text.Encoding.UTF8.GetBytes("the operator bot private id"));
			System.Diagnostics.Debug.WriteLine(Base32.Encode(hash).Substring(0, 39));*/
		}

		public void OnClientConnected(RemoteMachine.Node connectedNode)
		{
			Dictionary<int, object> factoryParams;

			foreach (string key in this.DistinctCommandKeys)
			{
				foreach (Network.Protocol.UCMD.UserCommandAttribute attrib in this.BotCommands[key].GetType().GetCustomAttributes(typeof(Network.Protocol.UCMD.UserCommandAttribute), false)
					.Where(p => p is Network.Protocol.UCMD.UserCommandAttribute))
				{
					if (string.IsNullOrEmpty(attrib.Name))
						return;

					factoryParams = new Dictionary<int, object>();
					factoryParams.Add((int)FactoryCMD.ParameterEnum.Name, attrib.Name);
					factoryParams.Add((int)FactoryCMD.ParameterEnum.Context, (int)attrib.Context);
					factoryParams.Add((int)FactoryCMD.ParameterEnum.Message, string.Format(attrib.Message, LocalMachine.BotNode.GetCommandPrefixes(this)[0]));

					if (!string.IsNullOrEmpty(attrib.Presentation))
						factoryParams.Add((int)FactoryCMD.ParameterEnum.Presentation, attrib.Presentation);

					connectedNode.Connection.Send(new FactoryCMD().Create(ProtocolMessage.MessageTypeEnum.Info, factoryParams).ToString());
				}
			}
		}

		public override void HandleCommandMessage(RemoteMachine.Node sourceNode, string message)
		{
			CommandMessage theCommand = ParseMessage(sourceNode, message);

			if (theCommand == null || string.IsNullOrWhiteSpace(theCommand.Name))
				return; // invalid command structure

			if (theCommand.Name == null || !this.BotCommands.ContainsKey(theCommand.Name))
				return; // unknown command

			// Should launch this as an asynchronous handler so bots do not slow down the hub...
			BotReturnStatus ret = this.BotCommands[theCommand.Name].HandleCommandMessage(sourceNode, theCommand);
			if (!ret.Success || ret.Message.Length > 0)
			{
				if (ret.BroadcastMessage)
					this.SendBroadcastMessageFromBot(ret.Message);
				else
					this.SendEchoMessageFromBot(sourceNode, ret.Message);
			}
		}

		public bool HasSecurityBotPermission
		{
			get
			{
				return Security.Permission.HasPermission(this.SecurityIdentity, typeof(Security.Permissions.SecurityBotPermission));
			}
		}
	}
}
